package org.daochong.lang;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.sql.DataSource;

import org.daochong.lang.uai.UniteAccessInterfaceFactory;

public class Dao<T> implements IDao<T> {

	private JdbcTemplate jdbcTemplate;
	protected Class<T> beanClass = null;
	private DataSource dataSource;
	private UniteAccessInterfaceFactory uaiFactory;

	@SuppressWarnings("unchecked")
	public Dao() {
		Type genType = this.getClass().getGenericSuperclass();
		Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
		this.beanClass = (Class<T>) params[0];
	}

	public Dao(Class<T> clazz) {
		this.beanClass = clazz;
	}

	public DataSource getDataSource() {
		return dataSource;
	}

	public UniteAccessInterfaceFactory getUaiFactory() {
		return uaiFactory;
	}

	public void setUaiFactory(UniteAccessInterfaceFactory uaiFactory) {
		this.uaiFactory = uaiFactory;
	}

	public void setDataSource(DataSource dataSource) {
		this.dataSource = dataSource;
	}

	public JdbcTemplate getJdbcTemplate() {
		return jdbcTemplate;
	}

	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}

	public JdbcTemplate requestJdbcTemplate() {
		if (this.getJdbcTemplate() != null) {
			return this.getJdbcTemplate();
		} else if (this.getDataSource() != null) {
			return new JdbcTemplate(dataSource);
		} else if (this.getUaiFactory() != null) {
			return this.getUaiFactory().getTemplate(JdbcTemplate.class);
		} else {
			JdbcTemplate jdbc = JdbcTemplateFactory.getDefault().getJdbcTemplate();
			if (jdbc != null) {
				return jdbc;
			}
			throw new RuntimeException("JdbcTempate is Null");
		}
	}

	public T load(T obj) throws SQLException {
		return this.requestJdbcTemplate().load(obj);
	}

	public boolean create(T obj) throws SQLException {
		return this.requestJdbcTemplate().create(obj);
	}

	public boolean save(T obj) throws SQLException {
		return this.requestJdbcTemplate().save(obj);
	}

	public boolean exists(T obj) throws SQLException {
		return this.requestJdbcTemplate().isExists(obj);
	}

	public boolean delete(T obj) throws SQLException {
		return this.requestJdbcTemplate().delete(obj);
	}

	public List<T> list() throws SQLException {
		return this.requestJdbcTemplate().list("select * from " + BeanUtil.getOrmInfo(beanClass).getTableName(),
				beanClass);
	}

	public boolean delete(Object... keys) throws SQLException {
		return this.requestJdbcTemplate().delete(beanClass, keys);
	}

	public T load(Object... keys) throws SQLException {
		return this.requestJdbcTemplate().load(beanClass, keys);
	}

	public boolean exists(Object... keys) throws SQLException {
		return this.requestJdbcTemplate().isExists(beanClass, keys);
	}

	public boolean updateWithoutNull(T obj) throws SQLException {
		return this.requestJdbcTemplate().updateWithoutNull(obj);
	}

	public boolean updatePart(Map<String, Object> data, String... keys) throws SQLException {
		String tableName = BeanUtil.getOrmInfo(beanClass).getTableName();
		return this.requestJdbcTemplate().update(data, tableName, keys);
	}

	public List<T> list(Map<String, Object> params) {
		List<T> list = null;
		try {
			List<Object> listParams = new ArrayList<Object>();
			StringBuilder sql = new StringBuilder(
					"select * from " + BeanUtil.getOrmInfo(beanClass).getTableName() + " where 1 = 1 ");
			if (null != params && params.size() > 0) {
				Iterator<String> fields = params.keySet().iterator();
				if (fields.hasNext()) {
					String field = fields.next();
					String column = BeanUtil.getOrmInfo(beanClass).getColumn(field);
					String value = (String) params.get(field);
					if (value == null) {
						sql.append(" and " + column + " is null ");
					} else {
						sql.append(" and " + column + " = ? ");
						listParams.add(params.get(field));
					}
				}
			}

			list = this.requestJdbcTemplate().list(sql.toString(), beanClass, listParams);
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException("queryList fail ");
		}

		return list;
	}

	public PageResult<T> list(Page page) {
		return this.list(page, new HashMap<String, Object>());
	}

	public PageResult<T> list(Page page, Map<String, Object> params) {
		List<Object> listParams = new ArrayList<Object>();
		StringBuilder sql = new StringBuilder(
				"select * from " + BeanUtil.getOrmInfo(beanClass).getTableName() + " where 1 = 1 ");
		if (null != params && params.size() > 0) {
			Iterator<String> fields = params.keySet().iterator();
			if (fields.hasNext()) {
				String field = fields.next();
				String column = BeanUtil.getOrmInfo(beanClass).getColumn(field);
				String value = (String) params.get(field);
				if (value == null) {
					sql.append(" and " + column + " is null ");
				} else {
					sql.append(" and " + column + " = ? ");
					listParams.add(params.get(field));
				}
			}
		}

		PageResult<T> pageResult = null;
		try {
			pageResult = this.requestJdbcTemplate().list(page, sql.toString(), beanClass, listParams.toArray());
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException("queryPage fail ");
		}
		return pageResult;
	}

	public PageResult<T> list(Page page, Map<String, Object> params, Map<String, String> orders) {
		List<Object> listParams = new ArrayList<Object>();
		StringBuilder sql = new StringBuilder(
				"select * from " + BeanUtil.getOrmInfo(beanClass).getTableName() + " where 1 = 1 ");
		if (null != params && params.size() > 0) {
			Iterator<String> fields = params.keySet().iterator();
			if (fields.hasNext()) {
				String field = fields.next();
				String column = BeanUtil.getOrmInfo(beanClass).getColumn(field);
				String value = (String) params.get(field);
				if (value == null) {
					sql.append(" and " + column + " is null ");
				} else {
					sql.append(" and " + column + " = ? ");
					listParams.add(params.get(field));
				}
			}
		}

		if (null != orders && orders.size() > 0) {
			sql.append(" ORDER BY ");
			Iterator<String> keys = orders.keySet().iterator();
			if (keys.hasNext()) {
				String field = keys.next();
				String value = orders.get(field);
				sql.append(field + " " + value + ",");
			}
			sql.deleteCharAt(sql.length() - 1);
		}

		PageResult<T> pageResult = null;
		try {
			pageResult = this.requestJdbcTemplate().list(page, sql.toString(), beanClass, listParams.toArray());
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException("queryPage fail ");
		}
		return pageResult;
	}

	public PageResult<T> list(Page page, String sql) throws SQLException {
		return requestJdbcTemplate().list(page, sql, beanClass);
	}

	public PageResult<T> list(Page page, String sql, List<Object> params) throws SQLException {
		return requestJdbcTemplate().list(page, sql, beanClass, params);
	}

	public PageResult<T> list(Page page, String sql, Map<String, Object> params) throws SQLException {
		return requestJdbcTemplate().list(page, sql, beanClass, params);
	}

}
